package com.sc.nft.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.sc.nft.annotation.UserLogin;
import com.sc.nft.annotation.UserRecordTimes;
import com.sc.nft.controller.request.*;
import com.sc.nft.entity.vo.EquityPoPonsolidatedPaymentDetailsVO;
import com.sc.nft.entity.vo.SecondEquityPropConfConfDetailsVO;
import com.sc.nft.entity.vo.SecondEquityPropTradingTendPageVO;
import com.sc.nft.entity.vo.secondEquityProp.*;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.exception.ModelException;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.SecondEquityPropsOrderService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.service.SecondEquityPropsService;
import com.sc.nft.sup.PageRequest;
import com.sc.nft.sup.PageResult;
import com.sc.nft.sup.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/second/equity/prop")
@Api(tags = "二级权益道具市场")
public class SecondEquityPropController {

    private final RedissonClient redisson;
    private final RedisTemplate redisTemplate;
    private final SecondEquityPropsOrderService secondOrderService;
    private final SecondEquityPropsService secondEquityPropService;

    @ApiOperation(value = "搜索商品", notes = "搜索商品", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/searchConf", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult<SecondEquityPropSearchConfVO> searchProduct(@Valid @RequestBody FirstTitlePageRequest request) {
        return PageResult.success(secondEquityPropService.searchProduct(request.getFirstTitle(), request.toMp()));
    }


    @ApiOperation(value = "大厅-列表", notes = "大厅-列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/confPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserRecordTimes
    @UserLogin
    public PageResult<SecondEquityPropConfPageVO> productPage(@Valid @RequestBody PageRequest request) {
        return PageResult.success(secondEquityPropService.productPage(request.toMp()));
    }

    @ApiOperation(value = "详情", notes = "详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/confDetails", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SecondEquityPropConfConfDetailsVO> confDetails(@Valid @RequestBody SecondConfIdRequest request) {
        return Result.success(secondEquityPropService.confDetails(request.getSecondConfId()));
    }

    @ApiOperation(value = "可购买列表", notes = "可购买列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getBuyProductPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserRecordTimes
    @UserLogin
    public PageResult<SecondEquityPropBuyProductPageVO> getBuyProductPage(@Valid @RequestBody SecondEquityPropBuyProductPageRequest request) {
        return PageResult.success(secondEquityPropService.getBuyProductPage(UserPool.getUser(), request.toMp(), request.getSecondConfId(), request.getSort()));
    }

    @ApiOperation(value = "订单计价", notes = "订单计价", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/buyValuation", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<RealAmountVO> valuation(@Valid @RequestBody SecondOrderValuationListRequest request) {
        return Result.success(secondOrderService.buyValuation(UserPool.getUser(), request.getEquityPropsId(), request.getOrderList()));
    }


    @ApiOperation(value = "商品计价", notes = "商品计价", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/productValuation", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<RealAmountVO> productValuation(@Valid @RequestBody SecondBuyValuationRequest request) {
        return Result.success(secondOrderService.valuation(UserPool.getUser(), request.getEquityPropsId(), request.getSecondProductIds()));
    }

    @ApiOperation(value = "锁单", notes = "锁单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/createOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserRecordTimes
    @UserLogin
    public Result<SecondEquityPropCreateOrderVO> createOrder(@Valid @RequestBody SecondBuyValuationRequest request) {
        String lockKey = StrUtil.format("{}{}", RedisKeyEnum.SECOND_USER_LOCK.getKey(), UserPool.getUser().getId());
        Boolean b = redisTemplate.hasKey(lockKey);
        if (b) {
            Integer lockSum = Convert.toInt(redisTemplate.opsForValue().get(lockKey));
            if (lockSum >= 3) {
                throw new GlobalRunTimeException(ErrorCode.ARE_MORE_THAN_3_UNPAID_ORDERS_ON_THE_DAY_WHICH_WILL_BE_AUTOMATICALLY_CANCELLED);
            }
        }
        SecondEquityPropCreateOrderVO vo = null;
        List<RLock> lock = new ArrayList();
        try {
            // 用来存放被锁的id
            List<Long> mallLockId = new ArrayList<>();
            request.getSecondProductIds().forEach(productId -> {
                // lock的key组成  LOCK_ORDER挂售id
                String key = StrUtil.format(RedisKeyEnum.LOCK_CONSIGN_EQUITY_PROPS.getKey(), productId);
                RLock orderLock = redisson.getLock(key);
                boolean heldByCurrentThread = orderLock.tryLock();
                if (!heldByCurrentThread) {
                    // 把挂载的商品id返回去.
                    mallLockId.add(productId);
                } else {
                    lock.add(orderLock);
                }
            });
            if (CollUtil.isNotEmpty(mallLockId)) {
                throw new ModelException(mallLockId, ErrorCode.COUNT_NOT_ENOUGH);
            }
            if (!UserPool.getUser().getIsSm()) {
                return Result.fail(ErrorCode.PLEASE_PERFORM_REAL_NAME_AUTHENTICATION_FIRST);
            }
            vo = secondOrderService.createOrder(UserPool.getUser(), request.getEquityPropsId(), request.getSecondProductIds());
        } finally {
            // 批量释放锁
            lock.forEach(rLock -> {
                rLock.unlock();
                log.info("二级释放Key:{}", rLock);
            });
        }
        redisTemplate.opsForValue().increment(lockKey);
        redisTemplate.expire(lockKey, 1, TimeUnit.HOURS);
        return Result.success(vo);
    }


    @ApiOperation(value = "成交趋势列表", notes = "成交趋势", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/tradingTendPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult<SecondEquityPropTradingTendPageVO> flowRecord(@Valid @RequestBody SecondEquityPropTradingTendPageRequest request) {
        return PageResult.success(secondOrderService.flowRecord(request.getEquityPropsId(), request.toMp()));
    }

    @ApiOperation(value = "成交趋势详情", notes = "成交趋势详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/tradingTendDetails", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SecondEquityPropTradingTendDetailsVO> tradingTendDetails(@Valid @RequestBody SecondEquityPropTradingTendDetailsRequest request) {
        return Result.success(secondOrderService.tradingTendDetails(request.getEquityPropsId()));
    }


    @ApiOperation(value = "买入订单,代付款订单,失效订单", notes = "买入订单/失效订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/buyOrderPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult<SecondEquityPropBuyOrderPageVO> orderPage(@Valid @RequestBody SecondEquityPropBuyOrderPageRequest request) {
        return PageResult.success(secondOrderService.orderPage(request.toMp(), UserPool.getUser(), request.getStatus(), request.getSearchTime()));
    }


    @ApiOperation(value = "买入订单详情", notes = "买入订单详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/buyOrderDetail", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SecondEquityPropBuyOrderPageVO> buyOrderDetail(@Valid @RequestBody IdRequest request) {
        SecondEquityPropBuyOrderPageVO orderPageVO = secondOrderService.buyOrderDetail(UserPool.getUser(), request.getId());
        return Result.success(orderPageVO);
    }

    @ApiOperation(value = "卖出订单详情", notes = "卖出订单详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/salesOrderDetail", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<SecondEquityPropBuyOrderPageVO> salesOrderDetail(@Valid @RequestBody IdRequest request) {
        SecondEquityPropBuyOrderPageVO orderPageVO = secondOrderService.salesOrderDetail(UserPool.getUser(), request.getId());
        orderPageVO.setReceiveIcon(null != orderPageVO.getReceiveType() ? orderPageVO.getReceiveType().getIcon() : null);
        return Result.success(orderPageVO);
    }

    @ApiOperation(value = "我出售的订单", notes = "我出售的订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/salesOrderPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public PageResult<SecondEquityPropBuyOrderPageVO> salesOrderPage(@Valid @RequestBody SecondEquityPropSalesOrderPageRequest request) {
        return PageResult.success(secondOrderService.salesOrderPage(request.toMp(), UserPool.getUser(), request.getSearchTime()));
    }

    @ApiOperation(value = "取消订单", notes = "取消订单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/batchCancelOrder", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result batchCancelOrder(@Valid @RequestBody SecondEquityPropCancelOrderRequest request) {
        secondOrderService.batchCancelOrder(request.getEquityPropsId(), request.getOrderIds(), UserPool.getUser());
        return PageResult.success();
    }

    @ApiOperation(value = "合并付详情", notes = "合并付详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/consolidatedPaymentDetails", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<EquityPoPonsolidatedPaymentDetailsVO> consolidatedPaymentDetails() {
        return Result.success(secondOrderService.consolidatedPaymentDetails(UserPool.getUser()));
    }


    @ApiOperation(value = "代付款订单详情(单个订单支付确认页)", notes = "代付款订单详情(单个订单支付确认页)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/waitPayOrderDetails", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<EquityPropWaitPayOrderDetailsVO> waitPayOrderDetails(@Valid @RequestBody SecondEquityPropOrderRequest request) {
        return Result.success(secondOrderService.waitPayOrderDetails(UserPool.getUser(), request.getOrderId()));
    }


}
